﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using Tycho.Language;
using Tycho.Parser.Peg;

namespace Tycho.Parser.GrammarExplorer
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private readonly string GrammarFileName;

        public Window1()
        {
            InitializeComponent();

            GrammarFileName = "expression.grammar";

            Source = "stuff";
            Grammar = File.ReadAllText (GrammarFileName);
            DataContext = this;
        }

        public string Source { get; set; }
        public string Grammar { get; set; }

        private void ParseButton_Click(object sender, RoutedEventArgs e)
        {
            errorsTextBox.Document.Blocks.Clear ();
            try {
                var compiledGrammar = new ParserLoader ().LoadParser (Grammar);

                ParseSource (compiledGrammar);
            } catch (SyntaxException se) {
                PrintSyntaxErrors (se);
                termsTextBox.Text = se.Term.ToString ();
            }
        }

        private void ParseSource (Grammar.IParser compiledGrammar) {
            ITerm term = compiledGrammar.ParseTerm (Source, null);

            termsTextBox.Text = term.ToString ();
        }

        private void PrintSyntaxErrors (SyntaxException se) {
            foreach (var syntaxError in se.SyntaxErrors) {
                IEnumerable<Inline> inlines = syntaxError.ExpectedProductions.Select (p => RenderProduction (p)).Where (i => i != null);
                int from = syntaxError.Term.SourceInformation.Index;
                int to = syntaxError.Term.SourceInformation.Index + syntaxError.Term.SourceInformation.Length;
                var paragraph = new Paragraph (new Run (from + "-" + to + ": expected "));
                AddErrors (inlines, paragraph);

                errorsTextBox.Document.Blocks.Add (paragraph);
            }
        }

        private void AddErrors (IEnumerable<Inline> inlines, Paragraph paragraph) {
            bool isFirst = true;
            foreach (Inline inline in inlines) {
                if (!isFirst) {
                    paragraph.Inlines.Add (new Run (" or "));
                } else {
                    isFirst = false;
                }

                paragraph.Inlines.Add (inline);
            }
        }

        private static Inline RenderProduction (IErrorInformation errorInformation) {
            if (errorInformation is ProductionErrorInformation) {
                var productionErrorInformation = (ProductionErrorInformation) errorInformation;
                return new Italic (new Run (productionErrorInformation.Name));
            } else if (errorInformation is KeywordErrorInformation) {
                var keyword = (KeywordErrorInformation) errorInformation;
                return new Bold (new Run (keyword.Keyword));
            } else if (errorInformation is RegexErrorInformation) {
                var regex = (RegexErrorInformation) errorInformation;
                var run = new Run ("/" + regex + "/");
                run.FontFamily = new FontFamily("Courier New");
                return run;
            } else {
                return null;
            }
        }

        private void SaveGrammarButton_Click(object sender, RoutedEventArgs e)
        {
            File.WriteAllText (GrammarFileName, Grammar);
        }
    }
}
